﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using OfficeOpenXml;
using OfficeOpenXml.Style;

namespace PhoneRater
{

    public partial class CalculateForm : Form
    {
        private Dictionary<int, string> _operatorByLine;
        private Dictionary<string, Calculator> _calculatorByOperator;
        private Dictionary<string, DataTable> _dataTableByName;

        public CalculateForm()
        {
            InitializeComponent();
        }

        private void CalculateForm_Load(object sender, EventArgs e)
        {
            this.rateByZoneRbISDNTableAdapter.Fill(this.calculateFormDataSet.RateByZoneRbISDN);
            this.rateByZoneRbBTCTableAdapter.Fill(this.calculateFormDataSet.RateByZoneRbBTC);
            this.rateByZoneTableAdapter.Fill(this.calculateFormDataSet.RateByZone);
            // каждая строка читает соответствующую таблицу на диске 
            // и записывает в локальную копию таблицы в ОЗУ
            this.ratesTableAdapter.Fill(this.calculateFormDataSet.Rates);
            this.operatorLinesTableAdapter.Fill(this.calculateFormDataSet.OperatorLines);
            FillCalls();
        }

        private void FillCalls()
        {
            var currentMonth = _selectedMonth.SelectionStart.Month + "/" + _selectedMonth.SelectionStart.Year;
            _lboxMessages.Items.Add("Обрабатываем данные за "+currentMonth);
            _lboxMessages.Refresh();

            this.callsTableAdapter.Fill(this.calculateFormDataSet.Calls, _selectedMonth.SelectionStart);
            // метод Fill требует второй параметр , т.к. на в дизайнере датасета
            // для таблицы calls переопределен (создан) SQL запрос получения данных
            // с параметром дата

            _operatorByLine = new Dictionary<int, string>();
            foreach (var operatorLine in calculateFormDataSet.OperatorLines)
            {
                _operatorByLine.Add(operatorLine.LineNumber, operatorLine.Operator);
            }

            // Словарь для обычных линий Белтелекома
            var zoneDictForBeltelecom = new Dictionary<string, Zone>();
            // Международные коды
            foreach (var row in calculateFormDataSet.RateByZone)
            {
                if (row.ZoneCode != null)
                    zoneDictForBeltelecom.Add(row.ZoneCode,
                            new Zone(row.CallZone, row.RateForDay, row.RateForNight));
            }
            // Коды по Беларуси
            foreach (var row in calculateFormDataSet.RateByZoneRbBTC)
            {
                zoneDictForBeltelecom.Add(row.ZoneCode,
                           new Zone(row.CallZone, row.RateForDay, row.RateForNight));
            }
            // Аналогично для ISDN линий
            var zoneDictForISDN = new Dictionary<string, Zone>();
            foreach (var row in calculateFormDataSet.RateByZone)
            {
                if (row.ZoneCode != null)
                    zoneDictForISDN.Add(row.ZoneCode,
                           new Zone(row.CallZone, row.RateForDay, row.RateForNight));
            }
            foreach (var row in calculateFormDataSet.RateByZoneRbISDN)
            {
                zoneDictForISDN.Add(row.ZoneCode,
                           new Zone(row.CallZone, row.RateForDay, row.RateForNight));
            }

            _calculatorByOperator = new Dictionary<string, Calculator>();
            _calculatorByOperator.Add("Velcom", new VelcomCalculator());
            _calculatorByOperator.Add("MTS", new MTSCalculator());
            _calculatorByOperator.Add("Beltelecom", new BeltelecomCalculator(
                                                     new ZoneParser(zoneDictForBeltelecom)));
            _calculatorByOperator.Add("ISDN", new BeltelecomCalculator(
                                                      new ZoneParser(zoneDictForISDN)));

            var errors = new HashSet<string>();
            foreach (var call in calculateFormDataSet.Calls)
            {
                var calculator = _calculatorByOperator[_operatorByLine[call.LineNumber]];
                if (_operatorByLine[call.LineNumber] == "Velcom") call.CallZone = "Velcom";
                if (_operatorByLine[call.LineNumber] == "MTS") call.CallZone = "МТС";

                var beltelecomCalculator = calculator as BeltelecomCalculator;
                if (beltelecomCalculator != null && beltelecomCalculator.ZoneParser != null)
                {
                    var zone = beltelecomCalculator.ZoneParser.Parse(call.PhoneNumber);
                    if (zone == null)
                    {
                        errors.Add("Не найден код зоны для "+call.PhoneNumber);
                        call.CallZone = "Не найден код зоны";
                        call.CallCost = 0;
                        continue;
                    }
                    call.CallZone = zone.Name;
                }
                call.CallCost = calculator.GetCost(call.Duration, call.TimeStamp, 
                                      call.PhoneNumber, _operatorByLine[call.LineNumber]);
            }
            ShowErrors(errors);
            _lboxMessages.Items.Add("");
            _lboxMessages.Items.Add("Вы можете выбрать другой месяц , за который необходимо построить отчеты");
            _lboxMessages.Refresh();
        }

        private void ShowErrors(ICollection<string> errors)
        {
            _lboxMessages.Items.Add("");
            foreach (var error in errors)
              _lboxMessages.Items.Add(error);
            _lboxMessages.Refresh();
        }

        private DateTime _currentMonth;

        private void OnMonthChanged(object sender, DateRangeEventArgs e)
        {
            if (_currentMonth.Month == _selectedMonth.SelectionStart.Month 
                     && _currentMonth.Year == _selectedMonth.SelectionStart.Year) return;
            _currentMonth = _selectedMonth.SelectionStart;
            FillCalls();
        }

        private void OnExportToExcelClick(object sender, EventArgs e)
        {
            _lboxMessages.Items.Clear();
            _lboxMessages.Items.Add("Идет запись расчитанных данных на диск...");
            _lboxMessages.Refresh();
            // сохраняем результаты расчет из ОЗУ в базу на диске
            this.Validate();
            this.callsTableAdapter.Update(this.calculateFormDataSet);
            _lboxMessages.Items.Add("Формируем данные для отчетов...");
            _lboxMessages.Refresh();
            // зачитываем данные сформированные запросом в аксесовской базе
            this.allOperatorsByMVZTableAdapter.Fill(this.reportsDataSet.AllOperatorsByMVZ, _selectedMonth.SelectionStart);
            this.beltelecomByMVZTableAdapter.Fill(this.reportsDataSet.BeltelecomByMVZ, _selectedMonth.SelectionStart);
            this.velcomByMVZTableAdapter.Fill(this.reportsDataSet.VelcomByMVZ, _selectedMonth.SelectionStart);
            this.mTSByMVZTableAdapter.Fill(this.reportsDataSet.MTSByMVZ, _selectedMonth.SelectionStart);
            this.allOperatorsByEmployeesTableAdapter.Fill(this.reportsDataSet.AllOperatorsByEmployees, _selectedMonth.SelectionStart);
            this.beltelecomByEmployeesTableAdapter.Fill(this.reportsDataSet.BeltelecomByEmployees, _selectedMonth.SelectionStart);
            this.velcomByEmployeesTableAdapter.Fill(this.reportsDataSet.VelcomByEmployees, _selectedMonth.SelectionStart);
            this.mTSByEmployeesTableAdapter.Fill(this.reportsDataSet.MTSByEmployees, _selectedMonth.SelectionStart);
            this.callsWithSurnamesTableAdapter.Fill(this.reportsDataSet.CallsWithSurnames, _selectedMonth.SelectionStart);

            _lboxMessages.Items.Add("Выгружаем отчеты в Excel...");
            _lboxMessages.Refresh();
            _dataTableByName = new Dictionary<string, DataTable>();
            _dataTableByName.Add("Все направления по кодам МВЗ", reportsDataSet.AllOperatorsByMVZ);
            _dataTableByName.Add("Белтелеком по кодам МВЗ", reportsDataSet.BeltelecomByMVZ);
            _dataTableByName.Add("Велком по кодам МВЗ", reportsDataSet.VelcomByMVZ);
            _dataTableByName.Add("МТС по кодам МВЗ", reportsDataSet.MTSByMVZ);
            _dataTableByName.Add("Все направления по сотрудникам", reportsDataSet.AllOperatorsByEmployees);
            _dataTableByName.Add("Белтелеком по сотрудникам", reportsDataSet.BeltelecomByEmployees);
            _dataTableByName.Add("Велком по сотрудникам", reportsDataSet.VelcomByEmployees);
            _dataTableByName.Add("МТС по сотрудникам", reportsDataSet.MTSByEmployees);

            string st =_selectedMonth.SelectionStart.Month.ToString();
            if (st.Length == 1) st = '0' + st;
            FileInfo newFile = new FileInfo(Path.Combine(Environment.CurrentDirectory,
                _selectedMonth.SelectionStart.Year + "-" + st + " PhoneRater Report.xlsx"));

            if (newFile.Exists) { newFile.Delete(); }

            ExcelPackage pck = new ExcelPackage(newFile);

            foreach (var dataTable in _dataTableByName)
            {
                WorkSheetFill(pck, dataTable.Key);
            }
            WorkSheet9thFill(pck, "CallsWithSurnames");

            pck.Save();
            _lboxMessages.Items.Add("Запускаем Excel...");
            _lboxMessages.Refresh();
            Process.Start(newFile.FullName);
            _lboxMessages.Items.Clear();
            _lboxMessages.Items.Add("Вы можете выбрать другой месяц , за который необходимо построить отчеты");
            _lboxMessages.Refresh();
        }

        private void WorkSheet9thFill(ExcelPackage pck, string tableName)
        {
            var ws = pck.Workbook.Worksheets.Add(tableName);
            ws.Cells["B1"].Value = "Сотрудник";
            ws.Cells["C1"].Value = "Вн.тел";
            ws.Cells["D1"].Value = "Дата/Время";
            ws.Cells["E1"].Value = "Длительность";
            ws.Cells["F1"].Value = "Линия";
            ws.Cells["G1"].Value = "Набранный номер";
            ws.Cells["H1"].Value = "Стоимость";
            ws.Cells["I1"].Value = "Направление звонка";
            ws.Cells["B1:I1"].Style.Font.Bold = true;

            int i = 1;
            decimal sum = 0;
            foreach (var line in reportsDataSet.CallsWithSurnames)
            {
                i++;
                ws.Cells['B' + i.ToString()].Value = line.SurName;
                ws.Cells['C' + i.ToString()].Value = line.InternalPhone;
                ws.Cells['D' + i.ToString()].Value = line.TimeStamp.ToString();
                ws.Cells['E' + i.ToString()].Value = line.Duration;
                ws.Cells['F' + i.ToString()].Value = line.LineNumber;
                ws.Cells['G' + i.ToString()].Value = line.PhoneNumber;
                ws.Cells['H' + i.ToString()].Value = line.CallCost;
                ws.Cells['I' + i.ToString()].Value = line.CallZone;
                sum += (decimal)line.CallCost;
            }
            i += 2;
            ws.Cells['H' + i.ToString()].Value = sum;
            ws.Cells['H' + i.ToString()].Style.Font.Bold = true;

            for (int j = 1; j <= 9; j++) { ws.Column(j).AutoFit(); }
            ws.Column(4).Style.HorizontalAlignment = ExcelHorizontalAlignment.Right;
            ws.Column(7).Style.HorizontalAlignment = ExcelHorizontalAlignment.Right;
        }

        private void WorkSheetFill(ExcelPackage pck, string tableName)
        {
            var ws = pck.Workbook.Worksheets.Add(tableName);
            ws.Cells["B1"].Value = "Код МВЗ";
            ws.Cells["C1"].Value = "Сумма";
            ws.Cells["A1:C1"].Style.Font.Bold = true;

            int i = 1;
            decimal sum = 0;

            DataTable dt = _dataTableByName[tableName];
            foreach (var line in (IEnumerable<DataRow>)dt)
            {
                i++;
                int j = 0;
                if (line.ItemArray.Count() == 3)
                {
                    ws.Cells["A1"].Value = "Сотрудник";
                    ws.Cells['A' + i.ToString()].Value = line[j];
                    j++;
                }
                ws.Cells['B' + i.ToString()].Value = line[j];
                ws.Cells['C' + i.ToString()].Value = line[j + 1];
                sum += (decimal)line[j + 1];
            }
            i += 2;
            ws.Cells['C' + i.ToString()].Value = sum;
            ws.Cells['C' + i.ToString()].Style.Font.Bold = true;

            for (int j = 1; j <= 3; j++) { ws.Column(j).AutoFit(); }
        }

        private void _btClose_Click(object sender, EventArgs e)
        {
            Close();
        }

    }
}
